<?php
declare(strict_types=1);

namespace Gwl\Framework\Routing;

use Gwl\Framework\Foundation\Application;
use Symfony\Component\HttpFoundation\Request;
use FastRoute\{DataGenerator, Dispatcher, RouteCollector, RouteParser};

class Router
{
    /**
     * @var Application $app
     */
    protected $app;

    protected $dispatcher;

    protected $collectorCallback;

    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    //加载路由
    public function loadRoutes($callback)
    {
        $this->collectorCallback = $callback;
    }

    public function dispatch(Request $request)
    {
        [$method, $uri] =  [$request->getMethod(), $request->getPathInfo()];
        $routeInfo = $this->createDispatcher()->dispatch($method, $uri);

        switch ($routeInfo[0]) {
            case Dispatcher::NOT_FOUND:
                $this->setNotFoundDecoratorMiddleware($uri);
                break;
            case Dispatcher::METHOD_NOT_ALLOWED:
                $this->setMethodNotAllowedDecoratorMiddleware($method);
                break;
            case Dispatcher::FOUND:
                return $this->execute($routeInfo[1], $routeInfo[2]);
                break;
        }
    }

    //格式化路由
    protected function execute($handler, $var)
    {
        if (is_callable($handler)){
            return call_user_func($handler, $var);
        }
        [$controller, $method] = explode("@", $handler, 2);
        return (new ControllerDispatcher($this->app))->dispatch($controller,$method);
    }

    protected function createDispatcher()
    {
        if ($this->dispatcher){
            return $this->dispatcher;
        }
        $routeCallBack = function (RouteCollector $r){
            ($this->collectorCallback)($r);
        };
        $this->dispatcher = \FastRoute\simpleDispatcher($routeCallBack);
        return  $this->dispatcher;
    }

    protected function setNotFoundDecoratorMiddleware($method)
    {
        throw new \RuntimeException("not found method {$method}");
    }

    protected function setMethodNotAllowedDecoratorMiddleware($allowed)
    {
        throw new \RuntimeException("not found method {$allowed}");
    }
}